using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Behaviors;

namespace Magiq.Update
{
    public class Update<T> : BehaviorHandler<IUpdateBehavior>, IUpdate<T> where T : class
    {
        private readonly List<IPropertySet> propertySets;

        public Update(IQueryable<T> queryable, IMagiqBehavior behavior)
            : base(behavior)
        {
            Source = queryable;
            propertySets = new List<IPropertySet>();
            Default<DefaultUpdateBehavior>();
        }

        #region IUpdate<T> Members

        public IUpdate<T> Set<TReturn>(Expression<Func<T, TReturn>> property, TReturn value)
        {
            Expression<Func<T, TReturn>> valueExpression = x => value;
            return Set(property, valueExpression);
        }

        public IUpdate<T> Set<TReturn>(Expression<Func<T, TReturn>> property, Expression<Func<T, TReturn>> value)
        {
         SetByLambdas(property, value);
            return this;
        }

        public int Execute()
        {
            if (propertySets.Count == 0)
            {
                var exception = new NoPropertiesToUpdateException();
                Behavior<IErrorBehavior>().Call(x => x.OnException(exception));
                throw exception;
            }
            var strategy = Call(x => x.GetUpdateStrategy(this));
            var result = Call(x => x.Execute(strategy));
            return result;
        }

        int IUpdate<T>.Update()
        {
            return Execute();
        }

        public IQueryable<T> Source { get; private set; }

        public IEnumerable<IPropertySet> PropertySets
        {
            get { return propertySets; }
        }

        public void SetByLambdas(LambdaExpression property, LambdaExpression value)
        {
            propertySets.Add(new PropertySet(property, value));
        }

        IMagiqBehavior IBehaviorBasedExecution.Behavior
        {
            get { return BehaviorChain; }
        }

        #endregion

        protected void AddPorpertySets(IEnumerable<IPropertySet> sets)
        {
            propertySets.AddRange(sets);
        }
    }
}